﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

using _18miljard.Config;

namespace _18miljard
{
	enum ReferrerType
	{
		BookMark,
		SameDomain,
		OtherDomain,
		Empty
	}

	public class LogWriter
	{
		private static object lockObject = new object();

		public static void Write(string line)
		{
			LogWriter.Write(line, true);
		}

		public static void WriteReferrer()
		{
			if (LogWriter.MustLog == false)
				return;

			if (HttpContext.Current != null)
			{
				if (HttpContext.Current.Request != null)
				{
					ReferrerType refType = ReferrerType.Empty;

					Uri uri = HttpContext.Current.Request.UrlReferrer;
					string referrerUrl = "";

					if (uri == null)
						refType = ReferrerType.BookMark;
					else
					{
						referrerUrl = uri.OriginalString.ToLower();

						if (referrerUrl.Contains("18miljard") || referrerUrl.Contains("localhost"))
							refType = ReferrerType.SameDomain;
						else
							refType = ReferrerType.OtherDomain;
					}

					if (refType == ReferrerType.BookMark || refType == ReferrerType.OtherDomain)
					{
						if (LogWriter.IsBot == false && WebConfig.LogBots == true)
							LogWriter.Write(LogWriter.UserAgent);

						LogWriter.Write("homepage visited through: " + (refType == ReferrerType.OtherDomain ? referrerUrl : "Bookmark / direct entry"));
					}

					if (refType == ReferrerType.Empty)
						LogWriter.Write("Empty referrer");
				}
			}
		}

		public static void Write(string line, bool ip)
		{
			if (string.IsNullOrEmpty(line))
				return;

			if (ip && (LogWriter.MustLog == false))
				return;

			try
			{
				StringWriter writer = LogWriter.GetWriter();

				LogWriter.WriteTime(writer);

				if (ip)
				{
					string ips = ObjectFormatter.CurrentIp;

					if (ips != null)
					{
						writer.Write(" "); writer.Write(ips); writer.Write(" ");
					}
				}

				writer.WriteLine(line);

				LogWriter.WriteToLog(writer);
			}
			catch
			{
				//no problem if, for some reason, logging fails.
			}
		}

		public static void Write(Exception e)
		{
			StringWriter writer = LogWriter.GetWriter();

			LogWriter.WriteTime(writer);
			writer.WriteLine("EXCEPTION: ");

			StringBuilder indent = new StringBuilder("  ", 64);

			Exception current = e;
			int count = 0;
			while (current != null && count < 10)
			{
				writer.Write(indent.ToString());
				writer.WriteLine(current.Message);
				indent.Append("  ");
				current = current.InnerException;
				count++;
			}
			writer.WriteLine(e.StackTrace);

			LogWriter.WriteToLog(writer);
		}

		private static bool IsBot
		{
			get
			{
				bool isBot = false;

				if (WebConfig.BotIpCollection.Contains(ObjectFormatter.CurrentIp))
					return true;

				string userAgent = LogWriter.UserAgent;

				if (string.IsNullOrEmpty(userAgent) == false)
					isBot = Regex.IsMatch(userAgent, WebConfig.BotPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase);

				return isBot;
			}
		}

		private static bool MustLog
		{
			get
			{
				bool isBot = LogWriter.IsBot;
				bool logBots = WebConfig.LogBots;

				return (logBots == true || isBot == false);
			}
		}

		private static string UserAgent
		{
			get
			{
				if (HttpContext.Current != null)
				{
					if (HttpContext.Current.Request != null)
					{
						return HttpContext.Current.Request.ServerVariables["HTTP_USER_AGENT"];
					}
				}

				return null;
			}
		}

		private static void WriteToLog(StringWriter writer)
		{
			string fileName = System.Web.Hosting.HostingEnvironment.MapPath("/App_Data/") + DateTime.Now.ToString("yyyy-MM-dd") + ".log";
			FileStream fileStream;

			lock (LogWriter.lockObject)
			{
				fileStream = File.Open(fileName, FileMode.Append, FileAccess.Write, FileShare.Write);
				StreamWriter streamWriter = new StreamWriter(fileStream);

				streamWriter.Write(writer.ToString());

				streamWriter.Flush();

				streamWriter.Close();
			}
		}

		public static void Copy(int lines, string outputFile, string inputFile)
		{
			string infileName = System.Web.Hosting.HostingEnvironment.MapPath("/App_Data/") + inputFile;
			string outfileName = System.Web.Hosting.HostingEnvironment.MapPath("/App_Data/") + outputFile;

			FileStream inStream = File.OpenRead(infileName);
			FileStream outStream = File.Open(outfileName, FileMode.Append, FileAccess.Write, FileShare.Write);
			StreamReader reader = new StreamReader(inStream);
			StreamWriter writer = new StreamWriter(outStream);

			for (int i = 0; i < lines; i++)
			{
				string line = reader.ReadLine();
				writer.WriteLine(line);
			}

			inStream.Close();
			outStream.Close();

		}

		private static void WriteTime(StringWriter writer)
		{
			writer.Write(DateTime.Now.ToString("yyyy-MM-dd, HH:mm:ss:fff - "));
		}

		private static StringWriter GetWriter()
		{
			return new StringWriter();
		}
	}
}